package org.redmagic.service.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.redmagic.service.domain.HierarchicalRequest;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public final class JsonUtils {

	private JsonUtils() {}
	
	/**
	 * Used to convert a JSONArray of JSONArray's into a List<List<String>>,
	 * so that it is easier to use by the service.  Note that this method will preserve the order
	 * of the nested arrays, but sort the string values inside of the arrays.  Example below.
	 * 
	 * Ex. Hierarchy Array Input  (JSONArray)
	 * [
	 *  [ "release=1.0", "localhost", "systemType=production" ],
	 *  [ "systemType=production", "release=1.0" ],
	 *  [ "release=1.0" ]
	 * ]
	 * 
	 * Ex. Hierarchy Output  (List<List<String>>)
	 * [
	 *  [localhost, release=1.0, systemType=production], 
	 *  [release=1.0, systemType=production], 
	 *  [release=1.0]
	 * ]
	 * 
	 * @param nestedArray
	 * 		A JSONArray representing the tagsHierarchy, i.e. an array of arrays.
	 * @return
	 * 		A List of Lists containing the sorted tags in the order of the input hierarchy.
	 * @throws JSONException
	 * 		Thrown when unable to retrieve an inner array.
	 */
	public static List<List<String>> fromNestedJsonArray(JSONArray nestedArray) throws JSONException {
		
		List<List<String>> results = new ArrayList<List<String>>(nestedArray.length());
		
		for (int hierarchyIndex = 0; hierarchyIndex < nestedArray.length(); hierarchyIndex++) {			
			JSONArray innerArray = nestedArray.getJSONArray(hierarchyIndex);
			List<String> sortedResult = fromJsonArray(innerArray);
			results.add(sortedResult);
		}
		
		return results;
	}
	
	/**
	 * Used to convert a JSONArray representing into a List<String>,
	 * so that it is easier to use by the service.  Note that this method will also sort the values.
	 * 
	 * Ex. Hierarchy Array Input  (JSONArray)
	 * [ "release=1.0", "localhost", "systemType=production" ]
	 * 
	 * Ex. Hierarchy Output  (List<String>)
	 * [localhost, release=1.0, systemType=production]
	 * 
	 * @param hierarchy
	 * 		A JSONArray of string values.
	 * @return
	 * 		A List containing the sorted values.
	 * @throws JSONException
	 * 		Thrown when unable to retrieve a value.
	 */
	public static List<String> fromJsonArray(JSONArray input) throws JSONException {
		
		List<String> results = new ArrayList<String>(input.length());
		for (int tagsIndex = 0; tagsIndex < input.length(); tagsIndex++) {
			results.add(input.getString(tagsIndex));
		}
		
		Collections.sort(results);
		return results;
	}
	
	public static JSONArray toNestedJsonArray(JSONArray... arrays) {
		return toNestedJsonArray(Arrays.asList(arrays));
	}
	
	public static JSONArray toNestedJsonArray(List<JSONArray> arrays) {
		JSONArray results = new JSONArray();
		for (JSONArray array : arrays) {
			results.put(array);
		}
		
		return results;
	}
	
	public static JSONArray toJsonArray(String... inputValues) {
		return toJsonArray(Arrays.asList(inputValues));
	}
	
	public static JSONArray toJsonArray(List<String> inputValues) {
		
		Collections.sort(inputValues);
		
		JSONArray results = new JSONArray();
		for (String inputValue : inputValues) {
			results.put(inputValue);
		}
		
		return results;
	}
	
	public static HierarchicalRequest toHierarchicalRequest(JSONObject jsonObject) throws JSONException {
		
		// parse out the hierarchy and properties
		JSONArray propertiesArray = jsonObject.getJSONArray(MongoProperties.PROPERTIES_KEY);
		JSONArray hierarchyArray = jsonObject.getJSONArray(MongoProperties.HIERARCHY_KEY);
		
		// convert to usable form
		List<String> properties = fromJsonArray(propertiesArray);
		List<List<String>> hierarchy = fromNestedJsonArray(hierarchyArray);
		
		// return object
		return new HierarchicalRequest(properties, hierarchy);
	}
	
	public static JSONObject toJsonObject(JSONArray hierarchy, JSONObject properties) throws JSONException {
		
		JSONObject jsonObject = new JSONObject();
		jsonObject.put(MongoProperties.HIERARCHY_KEY, hierarchy);
		jsonObject.put(MongoProperties.PROPERTIES_KEY, properties);
		return jsonObject;
	}
	
	public static HierarchicalRequest toHierarchicalRequest(String json) {
		Gson gson = new GsonBuilder().disableHtmlEscaping().create();
		return gson.fromJson(json, HierarchicalRequest.class);
	}
}
